package com.quectel.business.dms.application.access.accessor.im.impl;

import cn.hutool.crypto.digest.MD5;
import com.quectel.business.dms.application.ApplicationAccessConf;
import com.quectel.business.dms.application.access.accessor.im.AbstractIntelligentMonitorAccessor;
import com.quectel.business.dms.application.access.accessor.im.model.PlaybackPart;
import com.quectel.business.dms.application.access.accessor.im.model.StreamResp;
import com.quectel.business.dms.application.access.basemodel.ApplicationOriginDevice;
import com.quectel.constant.core.device.DeviceTypeCodeConstants;
import com.quectel.core.module.application.dto.ApplicationDto;
import com.quectel.core.module.device.dto.DeviceCommandTemplateDto;
import com.quectel.core.module.device.dto.DeviceDto;
import com.quectel.core.module.device.dto.DeviceTypeDto;
import com.quectel.core.module.device.service.DeviceTypeService;
import com.quectel.sdk.kuangshi.KsClientBuilder;
import com.quectel.sdk.kuangshi.monitor.MonitorClient;
import com.quectel.sdk.kuangshi.monitor.model.SyncDeviceResp;
import com.quectel.sdk.kuangshi.monitor.model.SyncVideoResp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 在这里编写说明
 *
 * @author: rananxin
 * @email: ryan.ran@quectel.com
 * @date: 2023-01-16 10:00:00
 */
@Component
@Slf4j
public class KuangshiBoxSubMonitorAccessorImpl extends AbstractIntelligentMonitorAccessor {

    @DubboReference
    private DeviceTypeService deviceTypeService;

    @Override
    public boolean initApplication(ApplicationDto application) {
        return syncOrRegisterDevices(application, null);
    }

    @Override
    public boolean syncOrRegisterDevices(ApplicationDto application, List<ApplicationOriginDevice> devices) {
        final Date currentDate = new Date();

        ApplicationAccessConf.TemplateOfKuangshiBoxConf templateOfKuangshiBoxConf = ApplicationAccessConf
                .parseExtStr(ApplicationAccessConf.TemplateOfKuangshiBoxConf.class, application.getAccessConf());

        try {
            assert templateOfKuangshiBoxConf != null;
            MonitorClient monitorClient = KsClientBuilder.builder()
                    .baseUrl(templateOfKuangshiBoxConf.getBaseUrl())
                    .username(templateOfKuangshiBoxConf.getUsername())
                    .password(templateOfKuangshiBoxConf.getPassword())
                    .build(MonitorClient.class);

            SyncDeviceResp syncDeviceResp = monitorClient.drawDevices();
            Long boxDeviceId = null;
            if (syncDeviceResp != null) {
                DeviceDto deviceDto = deviceService.selectByUniqueId(syncDeviceResp.getDeviceId(), application.getTenantId());
                DeviceTypeDto deviceTypeDto = deviceTypeService.selectByCode(DeviceTypeCodeConstants.KUANGSHI_BOX);
                if (deviceDto == null) {

                    deviceDto = new DeviceDto();
                    deviceDto.setUniqueId(syncDeviceResp.getDeviceId());
                    deviceDto.setImei(syncDeviceResp.getDeviceId());
                    deviceDto.setOriginName(syncDeviceResp.getDeviceModel());
                    deviceDto.setName(syncDeviceResp.getDeviceModel());
                    deviceDto.setDeviceTypeId(deviceTypeDto.getId());
                    deviceDto.setCreateTime(currentDate);

                    fill(deviceDto, application);
                    boxDeviceId = deviceService.save(deviceDto);
                } else {
                    List<DeviceDto> deviceDtos = deviceService.selectByApplicationId(application.getId());
                    Optional<DeviceDto> first = deviceDtos.parallelStream().filter(o -> o.getDeviceTypeId().equals(deviceTypeDto.getId())).findFirst();
                    if (first.isPresent()) {
                        boxDeviceId = first.get().getId();
                    }
                }
            }

            if (boxDeviceId != null) {
                log.debug("盒子设备同步成功，开始挂监控流设备");

                List<DeviceDto> deviceDtos = new ArrayList<>();

                SyncVideoResp syncVideoResp = monitorClient.drawVideos();
                if (syncVideoResp != null) {
                    List<SyncVideoResp.VideosCls> videos = syncVideoResp.getVideos();
                    for (SyncVideoResp.VideosCls videosCls : videos) {
                        try {
                            String uniqueId = MD5.create().digestHex(videosCls.getUrl(), StandardCharsets.UTF_8);
                            DeviceDto deviceDto = deviceService.selectByUniqueId(uniqueId, application.getTenantId());
                            if (deviceDto == null) {
                                deviceDto = new DeviceDto();
                                deviceDto.setUniqueId(uniqueId);
                                deviceDto.setImei(uniqueId);
                                deviceDto.setOriginName(videosCls.getVideoName());
                                deviceDto.setName(videosCls.getVideoName());
                                deviceDto.setParentId(boxDeviceId);
                                deviceDto.setCreateTime(currentDate);

                                fill(deviceDto, application);
                                deviceDtos.add(deviceDto);
                            } else if (!deviceDto.getApplicationId().equals(application.getId())) {
                                // 监控流切换到了另一个盒子
                                DeviceDto newlyDto = new DeviceDto();
                                newlyDto.setId(deviceDto.getId());
                                newlyDto.setParentId(boxDeviceId);
                                newlyDto.setApplicationId(application.getId());
                                deviceService.updateById(newlyDto);
                            }
                        } catch (Exception e) {
                            log.error("旷视 同步监控流异常", e);
                        }
                    }
                }
                deviceService.saveBatch(deviceDtos);
            }

            return true;
        } catch (Exception e) {
            log.error("旷视 监控同步 syncOrRegisterDevices 异常", e);
        }
        return false;
    }

    @Override
    public boolean subscribeEvents(ApplicationDto application) {
        return false;
    }

    @Override
    public boolean sendCmd(DeviceDto deviceDto, DeviceCommandTemplateDto deviceCommandTemplateDto, Map<String, Object> params, Long cmdId) {
        return false;
    }

    @Override
    public List<StreamResp> getStreamUrls(List<DeviceDto> monitors) {
        Map<Long, MonitorClient> instanceMap = new HashMap<>();

        List<String> streams = new ArrayList<>();
        for (DeviceDto monitor : monitors) {
            Long applicationId = monitor.getApplicationId();
            String url = "";
            try {
                MonitorClient monitorInstance = instanceMap.computeIfAbsent(applicationId, aLong -> {
                    ApplicationDto applicationDto = applicationService.selectById(aLong);
                    ApplicationAccessConf.TemplateOfKuangshiBoxConf templateOfKuangshiBoxConf = ApplicationAccessConf
                            .parseExtStr(ApplicationAccessConf.TemplateOfKuangshiBoxConf.class, applicationDto.getAccessConf());

                    assert templateOfKuangshiBoxConf != null;
                    return KsClientBuilder.builder()
                            .baseUrl(templateOfKuangshiBoxConf.getBaseUrl())
                            .username(templateOfKuangshiBoxConf.getUsername())
                            .password(templateOfKuangshiBoxConf.getPassword())
                            .build(MonitorClient.class);
                });

                SyncVideoResp syncVideoResp = monitorInstance.drawVideos();
                if (syncVideoResp != null) {
                    List<SyncVideoResp.VideosCls> videos = syncVideoResp.getVideos();
                    for (SyncVideoResp.VideosCls videosCls : videos) {
                        String uniqueId = MD5.create().digestHex(videosCls.getUrl(), StandardCharsets.UTF_8);
                        if (monitor.getUniqueId().equals(uniqueId)) {
                            url = videosCls.getUrl();
                            break;
                        }
                    }
                }
            } catch (Exception e) {
                log.error("旷视 监控对接 getStreamUrls 异常", e);
            }
            streams.add(url);
        }
        return streams.stream().map(v -> {
            if (v == null) {
                return null;
            }
            return new StreamResp(v, StreamResp.StreamType.RTSP);
        }).collect(Collectors.toList());
    }

    @Override
    public List<PlaybackPart> getPlaybackParts(DeviceDto monitor, Date startTime, Date endTime) {
        return Lists.newArrayList();
    }
}
